package com.zhiche.lisa.bms.service.bill.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zhiche.lisa.bms.dao.mapper.bill.BillIoMapper;
import com.zhiche.lisa.bms.dao.model.bill.BillIo;
import com.zhiche.lisa.bms.dao.model.bill.BillIoDetail;
import com.zhiche.lisa.bms.pojo.dto.util.CustBillDTO;
import com.zhiche.lisa.bms.pojo.dto.util.CustBillDetailDTO;
import com.zhiche.lisa.bms.service.bill.BillIoDetailService;
import com.zhiche.lisa.bms.service.bill.BillIoService;
import com.zhiche.lisa.bms.service.utils.OtmUtil;
import com.zhiche.lisa.core.supports.BaseException;
import com.zhiche.lisa.core.utils.Account.AccountUtil;
import com.zhiche.lisa.core.utils.Account.JwtAccountVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 客户或承运商账单 服务实现类
 * </p>
 *
 * @author WangShuiJin
 * @since 2018-09-06
 */


@Service
@Slf4j
public class BillIoServiceImpl extends ServiceImpl<BillIoMapper, BillIo> implements BillIoService {
    static final String INCOME_BILL = "AR";//应收账单
    static final String PAYMENT_BILL = "AP";//应付账单

    @Autowired
    private BillIoDetailService billIoDetailService;

    @Autowired
    private OtmUtil otmUtil;

    /**
     * 查询客户或承运商账单列表（分页）
     *
     * @param page     分页/查询条件
     * @param billType 账单类型
     * @return
     */
    @Override
    public Page<BillIo> queryBillIoPage(Page<BillIo> page, String billType) {
        EntityWrapper<BillIo> ew = this.queryLikeCheck(page.getCondition(), billType);
        //清空page附加条件值
        page.setCondition(Maps.newHashMap());
        page.setRecords(baseMapper.selectPage(page, ew));
        return page;
    }

    /**
     * 新增客户或承运商账单
     *
     * @param billIo
     * @return
     */
    @Override
    public Long insertBillIo(BillIo billIo) {
        if (ObjectUtils.isEmpty(billIo)) {
            throw new BaseException("新增参数不能为空！");
        }
        boolean result = this.insert(billIo);
        if (!result) {
            throw new BaseException("新增客户或承运商账单，失败！");
        }
        return billIo.getId();
    }

    /**
     * 模糊查询条件
     *
     * @param condition 模糊查询字段
     * @param billType  账单类型
     * @return
     */
    private EntityWrapper<BillIo> queryLikeCheck(Map<String, Object> condition, String billType) {
        if (!INCOME_BILL.equals(billType) && !PAYMENT_BILL.equals(billType)) {
            throw new BaseException("账单类型不能为空，至少是 [应收账单/应付账单] 其中一个！");
        }
        EntityWrapper<BillIo> ew = new EntityWrapper<>();
        //账单类型([应收账单(AR)：客户账单],[应付账单(AP)：承运商账单])
        ew.orderBy("gmt_create desc, id desc");
        ew.eq("bill_type", String.valueOf(billType));
        if (!CollectionUtils.isEmpty(condition)) {
            //遍历条件
            for (Map.Entry<String, Object> entry : condition.entrySet()) {
                if (!Strings.isNullOrEmpty(entry.getKey())) {
                    //账单编号
                    if ("billCode".equals(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                        ew.like("bill_code", String.valueOf(entry.getValue()));
                    }

                    if (billType.equals(INCOME_BILL)) {//应收账单
                        if ("customer".equals(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                            ew.like("payer_id", String.valueOf(entry.getValue())); //客户=付款方
                        }
                    } else if (billType.equals(PAYMENT_BILL)) {//应付账单
                        if ("customer".equals(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                            ew.like("payee_id", String.valueOf(entry.getValue()));//客户=收款方
                        }
                    }
                    // 收款方
                    if ("payeeId".equals(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                        ew.eq("payee_id", String.valueOf(entry.getValue()));
                    }
                    //客户
                    if ("proprietor".equals(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                        ew.like("proprietor", String.valueOf(entry.getValue()));
                    }
                    //账单状态(0.新增/1.已出账/2.对账中/3.已确认/4.已结算/5.已结算)
                    if ("billStatus".equals(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                        ew.like("bill_status", String.valueOf(entry.getValue()));
                    }
                    //出账开始时间
                    if ("beginDate".equals(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                        ew.ge("publish_time", entry.getValue());
                    }
                    //出账结束时间
                    if ("endDate".equals(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                        ew.le("publish_time", entry.getValue());
                    }
                }
            }
        }
        return ew;
    }

    /**
     * 准确查询条件
     *
     * @param billCode 账单编号
     * @param billType 账单类型
     * @return
     */
    private EntityWrapper<BillIo> queryExactCheck(String billCode, String billType) {
        if (!StringUtils.hasText(billCode)) {
            throw new BaseException("账单编号不能为空！");
        }
        if (!INCOME_BILL.equals(billType) && !PAYMENT_BILL.equals(billType)) {
            throw new BaseException("账单类型不能为空，至少是 [应收账单/应付账单] 其中一个！");
        }
        EntityWrapper<BillIo> ew = new EntityWrapper();
        ew.eq("bill_code", billCode).eq("bill_type", billType).eq("is_delete", "0");
        return ew;
    }

    /**
     * 根据账单编号和类型，得到一条客户或承运商账单
     *
     * @param billCode 账单编号
     * @param billType 账单类型
     * @return
     */
    @Override
    public BillIo getBillIoByTypeAndCode(String billCode, String billType) {
        EntityWrapper<BillIo> ew = queryExactCheck(billCode, billType);
        List<BillIo> billIo = baseMapper.selectListNoTenant(ew);
        if (!CollectionUtils.isEmpty(billIo)) {
            return billIo.get(0);
        }
        return null;
    }

    /**
     * 删除客户或承运商账单
     *
     * @param billCode 账单编号
     * @param billType 账单类型
     */
    @Override
    public void deleteBillIo(String billCode, String billType) {
        EntityWrapper<BillIo> ew = queryExactCheck(billCode, billType);
        boolean result = this.delete(ew);
        if (!result) {
            throw new BaseException("删除" + billType + "，失败！");
        }
    }

    /**
     * 查询客户或承运商的客户列表
     *
     * @param billType 账单类型
     * @return
     */
    @Override
    public List<BillIo> queryBillIoCustomerList(String billType) {
        EntityWrapper<BillIo> ew = this.queryLikeCheck(null, billType);
        if (INCOME_BILL.equals(billType)) {//应收账单
            ew.groupBy("payer_id"); //客户=付款方
        } else if (PAYMENT_BILL.equals(billType)) {//应付账单
            ew.groupBy("payee_id"); //客户=收款方
        }
        List<BillIo> billIos = this.selectList(ew);
        return billIos;
    }

    /**
     * 查询客户或承运商的账单状态
     *
     * @param billType
     * @return
     */
    @Override
    public List<String> getBillStatus(String billType) {
        EntityWrapper<BillIo> ew = this.queryLikeCheck(null, billType);
        ew.groupBy("bill_status");
        List<BillIo> billIos = this.selectList(ew);
        List<String> list = Lists.newArrayList();
        billIos.forEach(billIo -> {
            list.add(billIo.getBillStatus());
        });
        return list;
    }

    /**
     * 修改或承运商账单状态
     *
     * @param billCode
     * @param billStatus
     * @param billType
     */
    @Override
    public void updateBillIo(String billCode, String billStatus, String billType) {
        BillIo billIo = new BillIo();
        billIo.setBillStatus(billStatus);
        EntityWrapper<BillIo> ew = this.queryExactCheck(billCode, billType);
        this.update(billIo, ew);
    }

    /**
     * 无租户信息查询
     *
     * @param ew
     * @return
     */
    @Override
    public List<BillIo> selectListNoTenant(EntityWrapper ew) {
        return baseMapper.selectListNoTenant(ew);
    }

    /**
     * 根据code获取对应集合
     *
     * @param codes
     * @return
     */
    @Override
    public List<BillIo> selectBillListByBillCode(List<String> codes) {
        EntityWrapper<BillIo> billIoEntityWrapper = new EntityWrapper<>();
        billIoEntityWrapper.in("bill_code", codes);
        return this.selectList(billIoEntityWrapper);
    }

    /**
     * 批量推送BMS
     *
     * @param billCodeList
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void batchPushToBms(List<String> billCodeList) {
        if (!CollectionUtils.isEmpty(billCodeList)) {
            EntityWrapper<BillIo> ew = new EntityWrapper<>();
            ew.in("bill_code", billCodeList);
            List<BillIo> billIoList = this.selectListNoTenant(ew);
            if (!CollectionUtils.isEmpty(billIoList)) {
                for (BillIo billIo : billIoList) {
                    CustBillDTO custBillDTO = new CustBillDTO();
                    if ("30".equals(billIo.getBillStatus())) {
                        throw new BaseException("该客户账单已被确认，无法重复确认");
                    }
                    //验证登陆人tenantId
                    JwtAccountVO jwtAccountVO = AccountUtil.getAccountInfoFromSecurityContext();
                    if (ObjectUtils.isEmpty(jwtAccountVO)) {
                        throw new BaseException("未获取到登录信息");
                    }
                    // 账单状态（1 对账不平 3 对账成功）
                    custBillDTO.setBillStatus(3);
                    // 对账总数量
                    custBillDTO.setContNum(billIo.getNum());
                    // 账单编码
                    custBillDTO.setBillId(billIo.getBillCode());
                    //账单总金额
                    custBillDTO.setContTotal(String.valueOf(billIo.getGrossAmt()));
                    // 账单的对账时间
                    custBillDTO.setUploadTime(new Date());
                    // 账单对账操作人
                    custBillDTO.setUploadUser(jwtAccountVO.getAccountId());

                    List<CustBillDetailDTO> custBillDetailDTOList = getCustBillList(custBillDTO, billIo.getId());
                    if (!CollectionUtils.isEmpty(custBillDetailDTOList)) {
                        custBillDTO.setCustBillDetailList(custBillDetailDTOList);
                    }
                    billIo.setBillStatus("30");
                    String result = otmUtil.billContrastResult(custBillDTO);
                    log.info("批量推送BMS账单返回结果: {}", result);
                }
            }
            this.updateBatchById(billIoList);
        }
    }

    /**
     * 批量删除客户账单
     *
     * @param billIoIdList
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void batchDeleteBillIo(List<Long> billIoIdList) {
        if (CollectionUtils.isEmpty(billIoIdList)) {
            throw new BaseException("请选择数据");
        }
        List<BillIo> billIoList = this.selectBatchIds(billIoIdList);
        for (BillIo billIo : billIoList) {
            if (!"10".equals(billIo.getBillStatus())) {
                throw new BaseException(billIo.getBillCode() + ", 当前账单是非未对账状态, 不可删除!");
            }
        }
        this.deleteBatchIds(billIoIdList);
    }


    /**
     * 对象转换
     *
     * @param custBillDTO
     * @param headId
     * @return
     */
    private List<CustBillDetailDTO> getCustBillList(CustBillDTO custBillDTO, Long headId) {
        List<CustBillDetailDTO> custBillDetailDTOS = Lists.newArrayList();
        List<BillIoDetail> billIoDetailList = billIoDetailService.queryBillIoDetailList(headId);
        if (!CollectionUtils.isEmpty(billIoDetailList)) {
            BigDecimal[] totalSum = {BigDecimal.ZERO};
            billIoDetailList.forEach(billIoDetail -> {
                CustBillDetailDTO detailDTO = new CustBillDetailDTO();
                detailDTO.setId(billIoDetail.getId());
                //商品车型名称
                detailDTO.setCarTypeName(billIoDetail.getVehicleTypeName());
                //承运商对账明细单id
                detailDTO.setId(billIoDetail.getId());
                //计费公里数
                detailDTO.setMiles(billIoDetail.getKilometre());
                //创建时间
                detailDTO.setInsertTime(billIoDetail.getGmtCreate());
                //计费单价
                detailDTO.setPrice(billIoDetail.getActualPrice());
                detailDTO.setShipNum(billIoDetail.getNum());//数量
                detailDTO.setCustWaybillId(billIoDetail.getCustomerCode());//数量
                detailDTO.setSumMoney(billIoDetail.getActualAmt());//总金额
                //起运地
                detailDTO.setShipStartAddr(billIoDetail.getStartAddr());
                //目的地
                detailDTO.setShipEndAddr(billIoDetail.getEndAddr());
                //系统运单id
                detailDTO.setSysWaybillId(billIoDetail.getShipCode());
                //运输模式
                detailDTO.setTransModeId(billIoDetail.getTransModel());
                //对账时间
                detailDTO.setUploadTime(billIoDetail.getGmtModify());
                // 运输费
                detailDTO.setFare(billIoDetail.getFare());
                // 其他费用
                detailDTO.setOtherMoney(billIoDetail.getOtherMoney());
                //vin码
                detailDTO.setVin(billIoDetail.getVin());
                custBillDetailDTOS.add(detailDTO);
                if (billIoDetail.getActualAmt() != null) {
                    totalSum[0] = totalSum[0].add(billIoDetail.getActualAmt());
                }
            });
            //账单总金额 - 采用明细金额累加
            custBillDTO.setContTotal(String.valueOf(totalSum[0]));
        }
        return custBillDetailDTOS;
    }
}
